import os
import json
import serial
from datetime import datetime
from unzip import extract_archive
from PyQt5.QtCore import QThread, pyqtSignal
from watchdog.events import FileSystemEventHandler
from glom import glom

class SerialMonitorThread(QThread):
    
    status = pyqtSignal(str)
    data_received = pyqtSignal(str)
    file_complete = pyqtSignal(str)
    request_check_devices = pyqtSignal()
    task_signal = pyqtSignal(bool)

    def __init__(self, port_name, baudrate=15000000):
        super().__init__()
        self.port_name = port_name
        self.baudrate = baudrate
        self.serial_connection = None
        self.is_running = True
        self.current_file = None
        self.reveive_file = False
        self.buffer = b''
        

    def run(self):
        self.data_received.emit(f"当前波特率： {self.baudrate} ")
        while self.is_running:
            try:
                if not self.serial_connection or not self.serial_connection.is_open:
                    self.serial_connection = serial.Serial(self.port_name, baudrate=self.baudrate, timeout=0.05)
                    self.status.emit(f"已连接： {self.port_name} ")
                    self.data_received.emit(f"波特率： {self.baudrate} ")
                    self.data_received.emit(f"已连接： {self.port_name} ")
                if self.serial_connection.in_waiting > 0:
                    data = self.serial_connection.read(self.serial_connection.in_waiting)
                    self.process_data(data)
                else:
                    QThread.msleep(10)
            except Exception as e:
                self.data_received.emit(f"错误: {str(e)}")
                if self.serial_connection:
                    self.serial_connection.close()
                    self.serial_connection = None
                QThread.msleep(1000)  # Wait before retrying
                self.request_check_devices.emit()
                
    def detect_data_type(self, data:bytes):
        if not data:
            return "empty"
        try:
            decoded = data.decode()
            printable_radio = sum(ch.isprintable() or ch in "\r\n" for ch in decoded) / len(decoded)
            return "text" if printable_radio > 0.9 else "binary"
        except Exception:
            return "binary"
    
    def is_json_text(self, data:bytes):
        """判断数据是否为JSON文本"""
        try:
            text = data.decode().strip()
            if text.startswith("{") and text.endswith("}"):
                json.loads(text)
                return True
            return False
        except Exception:
            return False

    def process_data(self, data):
        try:
            self.buffer += data
            
            if self.reveive_file:
                try:
                    if "//end" in data.decode():
                        self.reveive_file = False
                        self.task_signal.emit(False)
                        print(f"文件末尾")
                        self.data_received.emit(f"文件末尾")
                    else:
                        self.file_data += data
                except Exception as e:
                    print(f"e:{e}")
                    self.file_data += data
                self.buffer = b''
               
            elif self.is_json_text(self.buffer):
                self.task_signal.emit(False)
                print(self.buffer.decode('utf-8'))
                json_data = json.loads(self.buffer.decode('utf-8'))
                if json_data.get("type") == "file":
                    content = json_data.get("content", {})
                    filename = content.get("filename", "temp_file")
                    size = content.get("size", 0)
                    extensions = content.get("extensions", "")
                    stream = content.get("stream", "")
                    extend = json_data.get("extend", {})
                
                    if stream == "start":
                        self.reveive_file = True
                        current_date = datetime.now().strftime("%Y-%m-%d")
                        self.current_file = os.path.join(current_date, filename)
                        self.file_data = b''
                        self.data_received.emit(f"文件传输已开始：{self.current_file}")
                    elif stream == "end":
                        self.reveive_file = False
                        if self.current_file:
                            
                            save_path = os.path.join(os.getcwd(), "received_files", self.current_file)
                            os.makedirs(os.path.dirname(save_path), exist_ok=True)
                            
                            with open(save_path, "wb") as f:
                                f.write(self.file_data)
                            self.current_file = None
                            self.file_data = b''
                            
                            self.data_received.emit("文件传输完成！")
                            
                            tasks = []
                            if "type" in extend:
                                type = extend.get("type")
                                print(f"type:{type}, extensions:{extensions}")
                                if type == "ht":
                                    if extensions == "zip" or extensions == "rar" or extensions == "7z":
                                        # 解压
                                        p = extract_archive(save_path)
                                        if p:
                                            print(f"type:{type} 解压，打开{p}")
                                            # os.startfile(p)
                                            with open(os.path.join(p, "ht.json"), encoding="utf-8") as f:
                                                file_data = json.load(f)
                                                relationship = file_data.get("relationship", [])
                                                # [{lable:'', xpath:'',jsonPath:'', type:''}]
                                                data = file_data.get("data", {})
                                                for item in relationship:
                                                    label = item.get("label", "")
                                                    xpath = item.get("xpath", "")
                                                    type = item.get("type", "")
                                                    jsonPath = item.get("jsonPath", "")
                                                    value = None
                                                    try:
                                                        value = glom(data, jsonPath)
                                                    except:
                                                        pass
                                                    tasks.append({
                                                        "dsc": label,
                                                        "type": type,
                                                        "action": type,
                                                        "value": value,
                                                        "xpath": xpath
                                                    })
                                                
                                                self.file_complete.emit(json.dumps({"data": {"extend": extend, "file_path": p, "extensions": extensions, "tasks": tasks, "source": data}}))
                                        else:
                                            print(f"type:{type} 解压失败，打开{save_path}")
                                            os.startfile(os.path.dirname(save_path))
                                            self.file_complete.emit(json.dumps({"data": {"extend": extend, "file_path": save_path, "extensions": extensions, "tasks": tasks, "source": data}}))
                                    elif extensions == "json":
                                        try:
                                            print(f"file_data: {save_path}")
                                            with open(save_path, "r", encoding="utf-8") as f:
                                                
                                                file_data = json.load(f)
                                                print(f"file_data: {json.dumps(file_data)}")
                                                relationship = file_data.get("relationship", [])
                                                # [{lable:'', xpath:'',jsonPath:'', type:''}]
                                                data = file_data.get("data", {})
                                                
                                                # {
                                                #     "dsc": "选择文件",
                                                #     "type": "file",
                                                #     "action": "select",
                                                #     "value": "",
                                                #     "xpath": "yth_05.png,yth_0500.png"
                                                # }
                                                
                                                for item in relationship:
                                                    label = item.get("label", "")
                                                    xpath = item.get("xpath", "")
                                                    type = item.get("type", "")
                                                    jsonPath = item.get("jsonPath", "")
                                                    value = None
                                                    try:
                                                        value = glom(data, jsonPath)
                                                    except:
                                                        pass
                                                    tasks.append({
                                                        "dsc": label,
                                                        "type": type,
                                                        "action": type,
                                                        "value": value,
                                                        "xpath": xpath
                                                    })
                                                d = json.dumps({"data": {"extend": extend,  "file_path": save_path,"extensions": extensions, "tasks": tasks, "source": data}})
                                                self.file_complete.emit(d)
                                        except Exception as e:
                                            print(f"{e}")
                                    else: 
                                        os.startfile(os.path.dirname(save_path))
                                else:
                                    # 意向
                                    if extensions == "zip" or extensions == "rar" or extensions == "7z":
                                        # 解压
                                        p = extract_archive(save_path)
                                        if p:
                                            print(f"type:{type} 解压，打开{p}")
                                            # os.startfile(p)
                                            with open(os.path.join(p, "yx.json"), encoding="utf-8") as f:
                                                file_data = json.load(f)
                                                relationship = file_data.get("relationship", [])
                                                # [{lable:'', xpath:'',jsonPath:'', type:''}]
                                                data = file_data.get("data", {})
                                                for item in relationship:
                                                    label = item.get("label", "")
                                                    xpath = item.get("xpath", "")
                                                    type = item.get("type", "")
                                                    jsonPath = item.get("jsonPath", "")
                                                    value = None
                                                    try:
                                                        value = glom(data, jsonPath)
                                                    except:
                                                        pass
                                                    tasks.append({
                                                        "dsc": label,
                                                        "type": type,
                                                        "action": type,
                                                        "value": value,
                                                        "xpath": xpath
                                                    })
                                                
                                                self.file_complete.emit(json.dumps({"data": {"extend": extend, "file_path": p, "extensions": extensions, "tasks": tasks, "source": data}}))
                                        else:
                                            print(f"type:{type} 解压失败，打开{save_path}")
                                            os.startfile(os.path.dirname(save_path))
                                            self.file_complete.emit(json.dumps({"data": {"extend": extend, "file_path": save_path, "extensions": extensions, "tasks": tasks, "source": data}}))
                                    else:
                                        print(f"type:{type} 无需解压，打开{save_path}")
                                        self.file_complete.emit(json.dumps({"data": {"extend": extend, "file_path": save_path, "extensions": extensions, "tasks": tasks, "source": None}}))
                            else:
                                self.file_complete.emit(json.dumps({"data": {"extend": extend, "file_path": save_path, "extensions": extensions, "tasks": tasks, "source": None}}))
                                os.startfile(os.path.dirname(save_path))
                            
                    self.buffer = b''
            else:
                # try:
                #     if "\r\n" in data.decode():
                #         return
                # except Exception:
                #     pass
                # if self.detect_data_type(data) == "binary":
                    # print("二进制")
                try:
                    if "//end" in data.decode():
                        self.task_signal.emit(False)
                        self.reveive_file = False
                        self.buffer = b''
                except Exception as e:
                    print(f"e:{e}")
                    self.task_signal.emit(False)
                    self.data_received.emit(f"转换差异: {str(e)}")
                # else:
                #     print(f"非二进制：{data.decode()}")
                    
        except Exception as e:
            print(f"{e}")
            self.buffer = b''
            self.file_data = b''
            self.reveive_file = False
            self.current_file = None
            self.task_signal.emit(False)
            self.data_received.emit(f"错误: {str(e)}")

    def stop(self):
        self.is_running = False


class SerialDeviceHandler(FileSystemEventHandler):
    def __init__(self, main_window):
        super().__init__()
        self.main_window = main_window

    def on_created(self, event):
        if event.is_directory:
            return
        if "tty" in event.src_path.lower():
            self.main_window.check_serial_devices()


class SerialDeviceMonitorThread(QThread):
    request_check_devices = pyqtSignal()

    def __init__(self, interval=3000):
        super().__init__()
        self.interval = interval
        self.is_running = True

    def run(self):
        while self.is_running:
            self.request_check_devices.emit()
            QThread.msleep(self.interval)

    def stop(self):
        self.is_running = False
